<template>
  <div class="bpx-player-video-area" ref="videoArea">
    <div class="bpx-player-video-perch" @click="changePlay">
      <video ref="video" :muted="isMuted" crossorigin="anonymous" preload="auto"></video>
    </div>
    <canvas v-show="isSpeak" ref="canvas" id="canvas" :style="{ width: w + 'px', height: h + 'px' }">
      您的浏览器不支持canvas标签。
    </canvas>
    <div class="hover-box">
      <videoTopWrap :isFull="isFull"></videoTopWrap>
      <videoControlWrap :duration="duration" :currentTime="currentTime" :isPlay="isPlay" :isFullWeb="isFullWeb"
                        :isFull="isFull" :bufferedTime="bufferedTime">
      </videoControlWrap>
    </div>
    <videoStateWrap :isPlay="isPlay"></videoStateWrap>
  </div>
</template>

<script>
import videoTopWrap from './videoTopWrap.vue'
import videoStateWrap from './videoStateWrap.vue'
import videoControlWrap from './videoControlWrap.vue'
import Hls from 'hls.js';


export default {
  /**视频区*/
  name: 'videoArea',
  components: {
    videoTopWrap,
    videoControlWrap,
    videoStateWrap
  },
  inject: [
    "detailList",
    "isSpeak"
  ],
  data() {
    return {
      // link: 'http://vali-g1.cp31.ott.cibntv.net/youku/697446c85e14171c789dd2e19/030008010063EEE4E2010BE212B6CF96302AC3-4F0C-4E1C-85EC-C1951BACD94D.mp4?sid=167929725600010003194_00_B18920f2dde5e01b66b0d894b111478cb&sign=1ac94b68c382fdc16544442e8a85dd94&ctype=50&si=183&psid=85ac4a01039bd75c1105687b9bec8c1b41346',
      isPlay: true,
      isFullWeb: false,
      isFull: false,
      isMuted: this.$store.state.videoInfo.isMuted,
      // 之后替换为服务器提供的url https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'  'http://127.0.0.1:9090/poll/getVideoStream/aaa.m3u8'
      duration: 0,
      currentTime: 0,
      bufferedTime: 0,
      barrageList: [],
      lastText: [],
      w: 0,
      h: 0,
      dmList: [],
      videoUrl: null,
      opacityValue: 80,//弹幕清晰度
      areaValue: 0.5,//弹幕播放区域
      maxDammukShowRow: 12,//弹幕最大播放行数
      danmakuSizeValue: 8,//弹幕大小
      danmakuSpeedValue: 0.5,//弹幕播发速度,
      shieldUserList:[]
    }
  },
  methods: {
    //刷新静音状态
    refreshMuted() {
      this.isMuted = this.$store.state.videoInfo.isMuted
    },
    //改变播放状态
    changePlay() {
      this.isPlay = !this.isPlay
      if (this.isPlay) {
        let playPromise = this.$refs.video.play()
        if (playPromise != undefined) {
          playPromise.then(() => {
            this.$refs.video.play()
          }).catch(() => {

          })
        }
        this.draw()
      } else {
        this.$refs.video.pause()
        cancelAnimationFrame(this.dmMove);
      }
    },
    //调节音量
    changeVol(volNum) {
      this.$refs.video.volume = volNum
    },
    changeRate(rate) {
      this.$refs.video.playbackRate = rate
    },
    //切换视频画质
    changeQuality(quality) {
      console.log(quality)
      console.log("11")
      // 会卡住，触发立即质量级别切换到新的质量级别，将中止当前片段请求
      this.hls.currentLevel = quality
      // 很久，设置下一个加载片段的质量级别
      this.hls.loadLevel = quality
      // 触发下一个片段的质量级别切换。这最终可能会刷新已经缓冲的下一个片段
      this.hls.nextLevel = quality
    },
    //获取当前视频播放时间
    changeCurrentTime(currentTime) {
      this.$refs.video.currentTime = currentTime
    },
    changeFull() {
      this.isFull = !this.isFull
      //用于视频全屏时 弹幕适应屏幕大小
      setTimeout(() => {
        // 保存当前的绘图状态
        this.ctx.save();
        // 新的缩放比例
        const newScale = window.devicePixelRatio || 1;
        const rect = this.$refs.video.getBoundingClientRect();
        this.w = rect.right - rect.left;
        this.h = rect.bottom - rect.top;
        // 重新设置上下文的缩放因子为 1，即不进行缩放
        this.ctx.font = '16px SimHei, sans-serif';
        this.ctx.setTransform(1, 0, 0, 1, 0, 0);
        // 恢复之前保存的绘图状态
        this.ctx.restore();
      }, 100);
      if (this.isFull) {
        if (this.$refs.videoArea.requestFullscreen) {
          this.$refs.videoArea.requestFullscreen();
        } else if (this.$refs.videoArea.msRequestFullscreen) {
          this.$refs.videoArea.msRequestFullscreen();
        } else if (this.$refs.videoArea.mozRequestFullScreen) {
          this.$refs.videoArea.mozRequestFullScreen();
        } else if (this.$refs.videoArea.webkitRequestFullscreen) {
          this.$refs.videoArea.webkitRequestFullscreen();
        }
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        }
      }
    },
    initVideo(videoUrl) {
      if (Hls.isSupported()) {
        this.videoUrl = 'http://127.0.0.1:9090/poll/getVideoStream' + videoUrl;
        // this.videoUrl =  'http://127.0.0.1:9090/poll/getVideoStream/thutrangcl_2023-05-27-12-58-46_1685163526794a.m3u8';
        this.hls = new Hls()
        this.hls.loadSource(this.videoUrl)
        this.hls.attachMedia(this.$refs.video)
        // level = -1，自动切换码率码率。
        // this.hls.startLevel = -1;
        this.hls.on(Hls.Events.BUFFER_APPENDED, () => {
          this.duration = this.$refs.video.duration
        });
        this.hls.on(Hls.Events.LEVEL_SWITCHED, function () {
          console.log('Video quality level switched successfully!');
        });
        this.hls.on(Hls.Events.ERROR, function (event, data) {
          console.log('error');
          console.log(data);
        });
      } else if (this.$refs.video.canPlayType('application/vnd.apple.mpegurl')) {
        this.$refs.video.src = this.video_url;
      } else {
        // 兼容性处理
        console.log('请升级浏览器')
      }
    },
    //监听视频播放时间变化   将弹幕放入弹幕显示队列
    getTime() {
      this.$refs.video.addEventListener('timeupdate', () => {
        if (this.$refs.video === undefined || this.$refs.video === null) return;
        this.currentTime = this.$refs.video.currentTime
        // 获取当前视频播放时间
        const currentTimeNum = Math.floor(this.currentTime)
        //限制一秒中只调用一次该函数  防止无线调用消耗cup性能
        if (currentTimeNum == this.lastTime) {
          return
        }
        this.lastTime = currentTimeNum
        // 将小于视频播放时间的弹幕加入弹幕显示队列
        let i = 0
        while (this.dmList[i] && this.dmList[i].time <= currentTimeNum) {
          if (this.dmList[i].time == currentTimeNum) {
            this.shoot(this.dmList[i].talk, currentTimeNum,this.dmList[i].userId)
          }
          i++
        }
      })
      //视频缓存监听事件
      this.$refs.video.addEventListener('progress', () => {
        //无后续分片则不调用
        if (this.$refs.video === undefined || this.$refs.video === null) return
        if (this.$refs.video.buffered.length != 0) {
          this.bufferedTime = this.$refs.video.buffered.end(0) - this.$refs.video.buffered.start(0)
        }
      })
    },
    //弹幕显示队列
    async shoot(text, currentTimeNum,userId) {
      if (this.shieldUserList != undefined || this.shieldUserList != 0){
        console.log("shieldUserList=======================")
        console.log(this.shieldUserList)
        if (this.shieldUserList.indexOf(userId) !== -1){
          //如果弹幕被用户频屏蔽则不发送弹幕
          return
        }
      }
    //todo 调整弹幕大小 已发送弹幕大小不发生改变 bug
      // 1~4的随机整数 弹幕行数
      // 缩放系数 用于 弹幕大小改变时 弹幕行数，行距的改变
      let scaleFactor = 8 / this.danmakuSizeValue
      const rNum = Math.ceil(Math.random() * this.areaValue * this.maxDammukShowRow * scaleFactor)
      // 弹幕所在第几行
      const top = rNum * 10 / scaleFactor
      let left
      if (this.lastText[rNum]) {
        left = Math.max(this.w, this.lastText[rNum].left + this.lastText[rNum].dmWidth + 10)
      } else {
        left = this.w
      }
      const dmWidth = this.ctx.measureText(text).width
      const barrage = {
        text: text,
        top: top,
        left: left,
        dmWidth: dmWidth,
        currentTimeNum: currentTimeNum,
      }
      this.lastText[rNum] = barrage
      this.barrageList.push(barrage)
    },
    draw() {
      if (this.barrageList.length > 0) {
        this.ctx.clearRect(0, 0, this.w, this.h)
        for (let i = 0; i < this.barrageList.length; i++) {
          const item = this.barrageList[i]
          if (item.left + item.dmWidth <= 0) {
            this.barrageList.splice(i, 1);
            i--;
            continue;
          }
          item.left -= this.offset;
          this.ctx.fillStyle = "#fff"
          this.ctx.font = item.fontSize + "px 'Microsoft YaHei', '微软雅黑', sans-serif";
          this.ctx.fillText(item.text, item.left, item.top);
        }

      }
      this.dmMove = requestAnimationFrame(this.draw.bind(this));
    },
    //添加弹幕
    async addDanmaku(text) {
      const moment = require('moment');
      const formattedTime = moment().format('yyyy-MM-DD HH:mm:ss');
      // 提交弹幕到数据库
      let res = await this.$util.post('hilihili/danmaku/addDanmaku', {
        videoId: this.$route.params.id,
        userId: this.$store.state.userInfo.userId,
        time: this.currentTime,
        talk: text,
        createdAt: formattedTime
      })
      // token过期，重新登录
      if (res.code === 401) {
        this.$store.commit('logout')
        this.$store.commit('changeLogView')
        return
      }
      if (res.code != 200) return
      this.getDanmaku()
      this.shoot(text)
    },
    async getDanmaku() {
      let res
      // 获取弹幕数
      res = await this.$util.post('hilihili/danmaku/getDanmakuByvideo', {
        videoId: this.$route.params.id,
        time: this.currentTime
      })
      if (res.code != 200) return
      this.danmakuChange = this.$util.numChange(res.data.count)
      //获取弹幕
      this.dmList = res.data.danmakuList
    },
    initCanvas() {
      this.initialScale = window.devicePixelRatio;
      const {width, height} = this.$refs.canvas;
      // 重新设置 canvas 自身宽高大小和 css 大小。放大 canvas；css 保持不变，因为我们需要那么多的点
      this.$refs.canvas.width = Math.round(width * this.initialScale);
      this.$refs.canvas.height = Math.round(height * this.initialScale);
      this.$refs.canvas.style.width = width + 'px';
      this.$refs.canvas.style.height = height + 'px';
      this.ctx = this.$refs.canvas.getContext("2d")
      // 直接用 scale 放大整个坐标系，相对来说就是放大了每个绘制操作
      this.ctx.scale(this.initialScale, this.initialScale);
      //调整画布大小 和屏幕一样大小
      const rect = this.$refs.video.getBoundingClientRect();
      this.w = rect.right - rect.left;
      this.h = rect.bottom - rect.top;
      //弹幕滚动速度
      this.offset = this.danmakuSpeedValue
    },
    play(isPlay) {
      if (isPlay) {
        let playPromise = this.$refs.video.play()
        if (playPromise != undefined) {
          playPromise.then(() => {
            this.$refs.video.play()
          }).catch(() => {

          })
        }
        this.addViewsNumber()
      }
    },
    async addViewsNumber() {
      await this.$util.post('hilihili/video/addViewsNumber', {
        videoId: this.$route.params.id,
        userId: this.$store.state.userInfo.userId
      })
    }
  },

  mounted() {
    // this.video_url = 'http://ivi.bupt.edu.cn/hls/cctv1hd.m3u8'
    this.getDanmaku()
    this.getTime()
    this.initCanvas()
    if (this.isPlay) {
      this.draw()
    }
    this.$bus.on("updateShieldUserList",async (shieldUserList)=>{

      this.shieldUserList = shieldUserList;
    })
    // 监听添加弹幕
    this.$bus.on('addDm', async (text) => {
      this.addDanmaku(text)
    })
    this.$bus.on("setOpacityValue", async (opacityValue) => {
      this.ctx.globalAlpha = opacityValue
    })
    this.$bus.on("setAreaValue", async (areaValue) => {
      this.areaValue = areaValue
    })
    this.$bus.on("setDanmakuSizeValue", async (danmakuSizeValue) => {
      // 使用 Math.max 来确保最小值不小于 1
      this.danmakuSizeValue = 8 * danmakuSizeValue
      let fontSize = Math.round(10 * danmakuSizeValue)
      //奇数px 弹幕字体大小不显示 所以需要将奇数变为偶数
      if (fontSize % 2 != 0) {
        fontSize++
      }
      // 更新弹幕列表中所有弹幕的字体大小
      this.barrageList.forEach(barrage => {
        // 如果弹幕对象中已经存在 fontSize，则不再更新
        if (typeof barrage.fontSize === 'undefined') {
          barrage.fontSize = fontSize;
        }
      });
    })
    this.$bus.on("setDanmakuSpeedValue", async (danmakuSpeedValue) => {
      this.offset = danmakuSpeedValue
    })
    this.play(this.isPlay)
  }
}
</script>


<style scoped>
#canvas {
  position: absolute;
  top: 0;
  left: 0;
}

.bpx-player-video-area {
  flex: 1;
  background-color: #000;
  position: relative;
  height: 100%;
  width: 100%;
}

.bpx-player-video-perch {
  position: absolute;
  height: 100%;
  width: 100%;
  /* visibility: hidden; */
}

.bpx-player-video-perch video {
  height: 100%;
  width: 100%;
  /* object-fit: fill; */
  /* position: absolute;
  top: 0;
  left: 0; */
}

.hover-box {
  position: absolute;
  height: 100%;
  width: 100%;
  top: 0;
  visibility: hidden;
  transition: all .2s;
}

.bpx-player-video-area:hover .hover-box {
  visibility: visible;
}
</style>
